#pragma once
// 包装一个线程安全栈
#include <exception>
#include <memory>
#include <iostream>
#include <mutex>
#include <stack>
#include <thread>

struct empty_stack : public std::exception
{
    const char* what() const noexcept
    {
        return "try to pop from empty stack";
    }
};

template <typename T>
class threadsafe_stack
{
private:
    std::stack<T> data;
    mutable std::mutex m;

public:
    threadsafe_stack() {}
    threadsafe_stack(const threadsafe_stack& other)
    {
        std::lock_guard<std::mutex> lk(other.m);
        data = other.data;
    }
    threadsafe_stack& operator=(const threadsafe_stack&) = delete;

    void push(T new_value)
    {
        std::lock_guard<std::mutex> lk(m);
        data.push(new_value);
    }

    std::shared_ptr<T> pop()
    {
        std::lock_guard<std::mutex> lk(m);
        if (data.empty()) throw empty_stack();
        std::shared_ptr<T> res = std::make_shared<T>(data.top());
        data.pop();
        return res;
    }

    void pop(T& value)
    {
        std::lock_guard<std::mutex> lk(m);
        if (data.empty()) throw empty_stack();
        value = data.top();
        data.pop();
    }

    bool empty() const
    {
        std::lock_guard<std::mutex> lk(m);
        return data.empty();
    }

    size_t size() const
    {
        std::lock_guard<std::mutex> lk(m);
        return data.size();
    }
};